﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;

namespace UploadFuzzTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(() => SequentialFuzzTest(7000, 10000));

            t.Start();

            /*Thread t = new Thread(() => RandomFuzzTest(100, 0, 100 * (1024 * 1024)));

            t.Start();*/
        }

        void WriteLog(string log)
        {
            Action action = delegate()
            {
                textBox1.AppendText(log);

                textBox1.ScrollToCaret();
            };

            if (textBox1.InvokeRequired)
                textBox1.BeginInvoke(action);
            else
                action();
        }

        private void SequentialFuzzTest(int start, int end)
        {
            Action init = delegate()
            {
                toolStripProgressBar1.Maximum = end - start;
                toolStripProgressBar1.Value = 0;
            };

            if (statusStrip1.InvokeRequired)
                statusStrip1.BeginInvoke(init);
            else
                init();

            int errorCount = 0;

            for (int length = start; length < end; length++)
            {
                if (!DoFuzz(length))
                    errorCount++;

                Action update = delegate()
                {
                    toolStripStatusLabel1.Text = length.ToString();
                    toolStripProgressBar1.Value = length - start;
                };

                if (statusStrip1.InvokeRequired)
                    statusStrip1.BeginInvoke(update);
                else
                    update();
            }

            WriteLog("sequential fuzz complete. started at " + start + ". ended at " + end + ". error count: " + errorCount + "\r\n");
        }

        private void RandomFuzzTest(int count, int min, int max)
        {
            Action init = delegate()
            {
                toolStripProgressBar1.Maximum = count;
                toolStripProgressBar1.Value = 0;
            };

            if (statusStrip1.InvokeRequired)
                statusStrip1.BeginInvoke(init);
            else
                init();

            int errorCount = 0;

            Random r = new Random();

            for (int i = 0; i < count; i++)
            {
                int length = r.Next(min, max);

                if (!DoFuzz(length))
                    errorCount++;

                Action update = delegate()
                {
                    toolStripStatusLabel1.Text = length.ToString();
                    toolStripProgressBar1.Value = i;
                };

                if (statusStrip1.InvokeRequired)
                    statusStrip1.BeginInvoke(update);
                else
                    update();
            }

            WriteLog("random fuzz complete. ran " + count + " times. min " + min + ". max " + max + ". error count: " + errorCount + "\r\n");
        }
        
        private bool DoFuzz(int length)
        {
            CreateFuzzFile(length);

            if (UploadFuzzFile(length))
            {
                if (!IsFuzzFileMatch(length))
                {
                    WriteLog(length + " - corrupt\r\n");

                    return false;
                }
            }
            else
            {
                WriteLog(length + " - exception\r\n");

                return false;
            }

            return true;
        }

        private bool IsFuzzFileMatch(int length)
        {
            string fileName = GetFuzzFileName(length);
            string uploadedFileName = GetUploadedFuzzFileName(length);

            if (!File.Exists(fileName) || !File.Exists(uploadedFileName))
                return false;
            else if (new FileInfo(fileName).Length != new FileInfo(uploadedFileName).Length)
                return false;

            using (Stream source = File.OpenRead(fileName))
            using (Stream dest = File.OpenRead(uploadedFileName))
            {
                int i = 0;
                int j = 0;

                while (i != -1 && j != -1)
                {
                    i = source.ReadByte();
                    j = dest.ReadByte();

                    if (i != j)
                        return false;
                }

                return i == j;
            }
        }

        private string GetUploadedFuzzFileName(int length)
        {
            //return Path.Combine(@"C:\Dev\KrystalwareSvn\SlickUpload\trunk\Samples\AspNetWebFormsCs\Files", length.ToString() + ".txt");
            //return Path.Combine("\\\\lana\\files", length.ToString() + ".txt");
            return Path.Combine(@"D:\Dev\Krystalware\SlickUpload\trunk\Quickstart\AspNetWebFormsCs\Files", length.ToString() + ".txt");
        }

        private string GetFuzzFileName(int length)
        {
            return Path.Combine("c:\\fuzz", length.ToString() + ".txt");
        }

        private void CreateFuzzFile(int length)
        {
            string fileName = GetFuzzFileName(length);

            Random r = new Random();

            using (Stream s = File.Create(fileName))
            {
                byte[] buffer = new byte[length];

                for (int i = 0; i < buffer.Length; i++)
                    buffer[i] = (byte)r.Next('A', 'z');
                
                s.Write(buffer, 0, buffer.Length);
            }
        }

        private bool UploadFuzzFile(int length)
        {
            try
            {
                string fileName = GetFuzzFileName(length);

                WebClient client = new WebClient();

                byte[] responseBinary = client.UploadFile("http://localhost/QuickStartCs/SlickUpload.axd?handlerType=upload", fileName);
                //byte[] responseBinary = client.UploadFile("http://lana/fuzztest/SlickUpload.axd?uploadHandler=upload&uploadId=bla", fileName);
                //byte[] responseBinary = client.UploadFile("http://localhost/QuickStartCs/UploadHandler.aspx", fileName);

                string response = Encoding.UTF8.GetString(responseBinary);

                return !string.IsNullOrWhiteSpace(response);
            }
            catch
            {
                return false;
            }
        }
    }
}
